package br.ufrn.findabomb;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.ByteBuffer;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

/**
 * Find-a-Bomb client class
 * 
 * Universidade Federal do Rio Grande do Norte
 * @author Eduardo Silva
 * Written in: 12/09/2012
 */
public class FindABombActivity extends Activity {
	private final String SERVER_HOST = "http://";
	private final long TIMEOUT = 1*60*1000; // 1minute * 60 seconds * 1000ms
	private long ID;
	private PingThread pingThread;
	private long PING;

	/**
	 * Disconnect reasons for client
	 * @author Eduardo Silva
	 */
	private enum DisconnectReason {
		TIMEOUT,
		CONNECTION_EXPIRED
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_find_abomb);

		pingThread = new PingThread(); // initializes thread object
		
		// sets onClick event for connect button
		((Button) findViewById(R.id.button_connect)).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				String nick = ((EditText) findViewById(R.id.edit_user_id)).getText().toString();

				((TextView) findViewById(R.id.text_status)).setText("Connecting...");
				setVisible(R.id.connecting);
				setInvisible(R.id.edit_user_id);
				setInvisible(R.id.button_connect);
				setInvisible(R.id.text_enter_id);

				// invoke web service, if fails, show error msg
				// tries to read its own id
				try {
					FileInputStream fs = getApplicationContext().openFileInput(
							"FindABomb.dat");
					byte[] bytes = ByteBuffer.allocate(8).array();
					try {
						fs.read(bytes);
						ID = ByteBuffer.wrap(bytes).asLongBuffer().get();
					} catch (Exception e) {
						showError(e);
					}
				} catch (FileNotFoundException e) {
					// if fails, pick a new id from server
					try {
						FileOutputStream fo = getApplicationContext().openFileOutput("FindABomb.dat", MODE_PRIVATE);
						ID = Long.parseLong(serverRequest(SERVER_HOST + "/request_id"));
						fo.write(ByteBuffer.allocate(8).putLong(ID).array());
						fo.close();
					} catch (Exception e1) {
						showError(e1);
					}
				}
				// at this point, we already have an ID
				try {
					// enter friend game or create one
					// TODO create game
					
					// TODO join friend
					String res = serverRequest(SERVER_HOST + "/connect?" + ID + "&nick=" + nick + "&to=" /* TODO connect with who? */);
					// format: <status>
					if (res.compareTo("success") == 0) {
						// alright! just set up the game and enjoy playing
						setupGame();
					}
				} catch (MalformedURLException e) {
					showError(e);
				}
			}
		});
		
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.activity_find_abomb, menu);
		return true;
	}

	/**
	 * Sets an object visible, enabling all events when needed
	 * @param id ID of object (available in L.id)
	 */
	private void setVisible(int id) {
		View view = findViewById(id);
		view.setVisibility(View.VISIBLE);
		if (view instanceof Button) {
			view.setClickable(true);
			view.setFocusable(true);
		} else if (view instanceof EditText) {
			view.setClickable(true);
			view.setFocusable(true);
		}
	}

	/**
	 * Sets an object invisible, disabling all events
	 * @param id ID of object (available in L.id)
	 */
	private void setInvisible(int id) {
		View view = findViewById(id);
		view.setVisibility(View.INVISIBLE);
		view.setClickable(false);
		view.setFocusable(false);
	}

	/**
	 * Creates a error log (for debug)
	 * @param e exception threw to be logged
	 */
	private void showError(Exception e) {
		System.out.println("[FindABomb Error]: "+e.getMessage());
	}

	/**
	 * Disconnects from server, and updates the screen
	 * @param dr reason
	 */
	private void doDisconnect(DisconnectReason dr) {
		((TextView) findViewById(R.id.text_status)).setText("Disconnected: "+ dr.toString());
		setInvisible(R.id.connecting);
		setVisible(R.id.edit_user_id);
		setVisible(R.id.button_connect);
		setVisible(R.id.text_enter_id);
	}
	
	/**
	 * Sets up game widget and start playing =D
	 */
	private void setupGame(){
		
	}
	
	/**
	 * Runnable class for ping measuring
	 * @author Eduardo Silva
	 */
	private class PingThread extends Thread {
		private boolean running;
		@Override
		public void run() {
			running = true;
			PING = 0;
			while(running) {
				try {
					if (PING>TIMEOUT) {
						doDisconnect(DisconnectReason.TIMEOUT); // disconnects for timeout
					}
					wait(1); // waits 1ms to accurate measure
					PING+=1; // increases ping counter
				} catch (InterruptedException e) {
					showError(e);
				}
			}
		}
		/**
		 * Halts the execution
		 */
		public void halt() {
			running = false; // breaks the loop
		}
		
		/**
		 * Rather than run/start, avoid IlegalStateExceptions
		 */
		public void execute() {
			if (!this.isAlive()) this.start();
		}
	}

	/**
	 * Requests a page from server, also measures latency (and disconnects by timeout)
	 * @param page String with desired URL
	 * @return URL contents
	 * @throws MalformedURLException when URL is malformed
	 */
	private String serverRequest(String page) throws MalformedURLException {
		if (pingThread==null) pingThread = new PingThread();
		pingThread.execute(); // start measuring latency
		String data = (new URL(page)).getFile().toString(); // request url file
		pingThread.halt(); // latency was successful measured
		return data;
	}
}
